import rete
#import websocket
#from threading import *
import mimetypes
#import cgi
import base
import config
import os
import richiesta
import traceback
import importlib
import sys
import time
#import io
#import threading
import wsgi_compat

#http_max_post_size = 1024 * 1024
#versioneHTTP = "HTTP/1.1"
#versioniSupportate = ["HTTP/1.1","HTTP/1.0"]
#tipoR = {
	#100 : "Continue",
	#101 : "Switching Protocols",
	#200 : "OK",
	#201 : "Created",
	#202 : "Accepted",
	#203 : "Non-Authoritative Information",
	#204 : "No Content",
	#205 : "Reset Content",
	#206 : "Partial Content",
	#300 : "Multiple Choices",
	#301 : "Moved Permanently",
	#302 : "Found",
	#303 : "See Other",
	#304 : "Not Modified",
	#305 : "Use Proxy",
	#307 : "Temporary Redirect",
	#400 : "Bad Request",
	#401 : "Unauthorized",
	#402 : "Payment Required",
	#403 : "Forbidden",
	#404 : "Not Found",
	#405 : "Method Not Allowed",
	#406 : "Not Acceptable",
	#407 : "Proxy Authentication Required",
	#408 : "Request Time-out",
	#409 : "Conflict",
	#410 : "Gone",
	#411 : "Length Required",
	#412 : "Precondition Failed",
	#.07 : "Bond James Bond",
	#413 : "Request Entity Too Large",
	#414 : "Request-URI Too Large",
	#415 : "Unsupported Media Type",
	#416 : "Requested range not satisfiable",
	#417 : "Expectation Failed",
	#500 : "Internal Server Error",
	#501 : "Not Implemented",
	#502 : "Bad Gateway",
	#503 : "Service Unavailable",
	#504 : "Gateway Time-out",
	#505 : "HTTP Version not supported"
#}

#class RichiestaGET(base.Richiesta):
	##contiene gli header e il riferimento alla connessione
	#def __init__(self, intestazione, headers, connessione, parseQuery=True,keepAlive=False):
		#global versioneHTTP
		#self.keepAlive = keepAlive
		#cheCosa = intestazione[1]
		#self.intestazione = intestazione
		#self.gestita = False
		#self.contenuto = ""
		#self.headers = headers
		#self.gestoreRichiesta = gestisciHTTPSemplice
		#self.connessione = connessione
		#self.wsocket = False
		##if intestazione[2] not in versioniSupportate:
			##erroreHTTP(self,505)
			##return
		#self.query = {}
		#pezzi1 = cheCosa.split("?")
		#self.cheCosa = cheCosa[0]
		#if parseQuery and len(pezzi1) > 1:
			#self.query = cgi.parse_qs()
			#for q in self.query:
				#self.query[q] = self.query[q][0]
	#def gestisci(self):
		##thr = Thread(target=self.gestoreRichiesta,args=[self],name="Gestione di "+str(self.__class__)+", socket "+str(self.connessione.fileno()))
		##thr.daemon= True
		##thr.start()
		#self.gestoreRichiesta(self)
#class RichiestaPOST(RichiestaGET):
	#def __init__(self, intestazione, headers, connessione, contenuto, keepAlive = False):
		#super().__init__(intestazione, headers,connessione,parseQuery=False,keepAlive= keepAlive)
		#self.query = {}
		#self.contenuto = contenuto
		#pezzi = contenuto.split("&")
		##for p in pezzi:
		##	parti = p.split("=")
		##	self.query[parti[0]] = parti[1]
		#self.query= cgi.parse_qs(contenuto)
		#for q in self.query:
			#self.query[q] = self.query[q][0]
		##print(self.query)
	##def gestisci(self):
	##	RispostaSemplice(self, 200, {}, self.query['prova'])

#def richiestaHTTP(data,req,datiPrecedenti):
	#global http_max_post_size
	#print("-------RECV")
	##data = data.decode("UTF-8").lstrip()
	#requestHeaders = {}
	#connessione = req.connessione
	#haveHeader = False
	#ricezioneContenuto = False
	#lunghezzaContenuto = -1
	#contenuto = ""
	#intestazione = []
	#headers=[]
	#keepAlive = False
	#olddata = bytes()
	#if datiPrecedenti is not None:
		#olddata, contenuto, lunghezzaContenuto, ricezioneContenuto, haveHeader, intestazione,headers, keepAlive = datiPrecedenti
	#pos = 0
	#data = olddata + data
	#acapo = bytes("\r\n",encoding="UTF-8")
	#if not haveHeader:
		##gli header sono seguiti da \r\n\r\n
		#pos = data.find(acapo+acapo)
		#if pos > rete.pacchetto:
			#erroreHTTP(req, 413)
		#if pos != -1:   #se abbiamo gli header li parsiamo e mettiamo in dizionario
			#headers = data[0:pos].split(acapo)
			#intestazione = headers[0].decode("UTF-8").split()
			#assert(len(intestazione)==3)
			#tipoRichiesta = intestazione[0]
			#assert(len(intestazione[2])>0)
			#if intestazione[2] not in versioniSupportate:
				#erroreHTTP(req,505)
				#return (False,None)
			#for h in headers[1:]:
				#h = h.decode("UTF-8")
				#colon = h.find(":")
				#assert(colon != -1)
				#parti = h[0:colon],h[colon+1:]
				#valore = parti[1].split(",")
				#nvalore = []
				#for v in valore:
					#nvalore.append(v.strip())
				##Multiple message-header fields with the same field-name MAY be
				##present in a message if and only if the entire field-value for that
				##header field is defined as a comma-separated list [i.e., #(values)].
				#if parti[0] in requestHeaders:
					#requestHeaders[parti[0]] += nvalore
				#else:
					#requestHeaders[parti[0]] = nvalore
			#haveHeader = True
			#pos += 4 #saltiamo \r\n\r\n
			##il browser può richiedere il "keep-alive": riusa la stessa conessione per tot minuti
			#if "Connection" in requestHeaders and "keep-alive" in requestHeaders["Connection"]:
				#keepAlive = True
			#sockettitudine = websocket.checkSocket(requestHeaders)
			#req.log(str(headers[0])+", keep alive: "+str(keepAlive))
			#assert(len(tipoRichiesta)>0)
			#if tipoRichiesta == "POST": 
				##se è una richiesta post, dobbiamo anche leggere il contenuto, vedi dopo
				#ricezioneContenuto = True
				#assert ("Content-Length" in requestHeaders)
				#lunghezzaContenuto = int(requestHeaders['Content-Length'][0])
				#if lunghezzaContenuto > http_max_post_size:
					#erroreHTTP(req,413)
					#return(False,None)
			#elif tipoRichiesta == "GET": #altrimenti no
				#if not sockettitudine:
					#r = RichiestaGET(intestazione, requestHeaders, connessione, keepAlive = keepAlive)
					#r.gestisci()
					#if keepAlive:
						#return (True, None)
					#else:
						#return (False, None)
				#else:
					#r = websocket.RichiestaWS(intestazione, requestHeaders, connessione, keepAlive = True)
					#r.gestisci()
					#return (False,None)
			#else:
				#erroreHTTP(req,501)
				#return (False,None)
		#else:
			#return (True, (data, contenuto, lunghezzaContenuto, True,haveHeader,intestazione,headers,keepAlive))
	##lettura contenuto
	#if ricezioneContenuto and len(contenuto) < lunghezzaContenuto:
		#contenuto += str(data[pos:])
		#if len(contenuto) >= lunghezzaContenuto:
			##se è finito, ok andiamo.
			#r = RichiestaPOST(intestazione, requestHeaders, connessione, contenuto, keepAlive = keepAlive)
			#r.gestisci()
			#if keepAlive:
				#return (True, None)
			#else: return (False, None)
		#else:
			##se non è finito, aspettiamo un altro pacchetto
			#return (True, (data, contenuto, lunghezzaContenuto, True,haveHeader,intestazione,headers,keepAlive))
	#assert(base.NOT_REACHED)

#def gestisciHTTPSemplice(richiesta):
	#risorsa = richiesta.intestazione[1]
	#assert (risorsa[0] == "/")
	#reqModule = config.risolviPath(risorsa, statics = True)
	#if reqModule is None:
		#erroreHTTP(richiesta,404)
		#return
	#if not reqModule.statico:
		#try: 
			##preparazione della funzione da passare (vedi WSGI)
			#start_response = wsgi_compat.RispostaWSGI(richiesta)
			##2 sintassi supportate:
			##WebModule= pacchetto.modulo.sottomodulo
			##WebModule= pacchetto modulo.sottomodulo
			#pezzi = reqModule.percorso['WebModule'].split(" ")
			#if len(pezzi) == 2:
				#mod = pezzi[1]
				#path1 = os.path.realpath(pezzi[0])
				#if path1 not in sys.path:
					#sys.path.insert(0,path1)
			#else:
				#mod = pezzi[0]
			#modulo = importlib.import_module(mod)
			#environ = dict()
			#buff = io.BytesIO()
			#buff.write(bytes(richiesta.contenuto,encoding="UTF-8"))
			#buff.seek(0)
			#environ['wsgi.input']       	= buff
			#environ['wsgi.errors']      	= sys.stderr
			#environ['wsgi.version']     	= (1, 0)
			#environ['wsgi.multithread']  	= False
			#environ['wsgi.multiprocess']	= True
			#environ['wsgi.run_once']		= True
			#environ['wsgi.url_scheme'] 		= 'http'
			#environ['REQUEST_METHOD']		= richiesta.intestazione[0]
			#environ['PATH_INFO']			= richiesta.intestazione[1]
			#environ['SCRIPT_NAME']			= ''
			#environ['QUERY_STRING']			= ''
			#environ['SERVER_NAME']			= config.valori['SERVER']['Host']
			#environ['SERVER_PORT']			= config.valori['SERVER']['Port']
			#for each in richiesta.headers:
				#environ['HTTP_' + each.upper().replace("-","_")] = ", ".join(richiesta.headers[each])
			#if 'HTTP_CONTENT_TYPE' in environ:
				#environ['CONTENT_TYPE'] = environ['HTTP_CONTENT_TYPE']
			#if 'HTTP_CONTENT_LENGTH' in environ:
				#environ['CONTENT_LENGTH'] = environ['HTTP_CONTENT_LENGTH']
			#result = modulo.application(environ, start_response )
			#try:
				#for l in result:
					#start_response.scrivi(l)
			#except TypeError as e:
				#try:
					#start_response.scrivi(result)
				#except:
					#pass
			#finally:
				#start_response.manda()
		#except Exception as e:
			#raise (e)
	#else:
		#if reqModule.okServilo:
			##serviamo il file statico così com'è
			#mime, encoding = mimetypes.guess_type(reqModule.percorso, strict=False)
			#headers = {'Content-Type' : mime, 'Content-Length' : str(os.stat(reqModule.percorso).st_size)}
			#mandaHeaders(richiesta, 200, headers)
			#with open(reqModule.percorso,"rb") as f:
				#pack = f.read(rete.pacchetto)
				#while pack:
					#rete.scrivi(richiesta.connessione, pack)
					#pack = f.read(rete.pacchetto)
		#else:
			#erroreHTTP(richiesta,403)

#class RispostaSemplice:
    #def __init__(self, richiesta, httpStatus, headers, contenuto,lenContenuto = -1):
        #global tipoR, versioneHTTP
        #if richiesta.gestita:
            #return
        ##if httpStatus not in tipoR:
        ##    httpStatus = 500
        #lenContenuto = len(contenuto) if lenContenuto == -1 else lenContenuto
        #headers['Content-Length'] = lenContenuto
        #if "Content-Type" not in headers:
            #headers["Content-Type"] = "text/html;charset=UTF-8";
        #mandaHeaders(richiesta, httpStatus, headers)
        #rete.scrivi(richiesta.connessione, bytes(contenuto,encoding="UTF-8"), lenContenuto)
        #richiesta.gestita = True
        ##print(strRisposta)
        #if not richiesta.keepAlive:
            #rete.chiudi(richiesta.connessione)

#def mandaHeaders( richiesta, httpStatus, headers):
	#global tipoR, versioneHTTP
	#if richiesta.gestita:
		#return
	#if isinstance(httpStatus,int) or isinstance(httpStatus,float):
		#tipo = tipoR[httpStatus] if httpStatus in tipoR else "Unknown error"
		#eccetera = str(httpStatus) + " " + tipo
	#else:
		#eccetera = httpStatus
	#richiesta.fornitoContentLength= True
	#if 'Content-Length' not in headers:
		#richiesta.fornitoContentLength= False
	#intestaz = versioneHTTP + " " + eccetera + "\r\n"
	#rete.scrivi(richiesta.connessione, bytes(intestaz,encoding="UTF-8"), len(intestaz))
	#richiesta.log("\t" + intestaz)
	##lenContenuto = len(contenuto) if lenConenuto != -1 else lenContenuto
	#h = headerizza(headers)
	#rete.scrivi(richiesta.connessione, bytes(h,encoding="UTF-8"), len(h))
			
#def headerizza(array):
    #return "\r\n".join(str(p)+": "+str(array[p]) for p in array) + "\r\n\r\n"

#def erroreHTTP(richiesta,numero):
	#global tipoR
	#tipo = tipoR[numero] if numero in tipoR else "Unknown error"
	#rispo = RispostaSemplice(richiesta, numero, {}, "<h1>"+str(numero)+" "+tipo+"</h1>")
	

#def lowerAll(lista):
	#lista2 = []
	#for v in lista:
		#lista2 += v.lower()
	#return lista2
def erroreHTTP(req,numero,debug=""):
	tipoR = richiesta.HttpUtils.errors
	tipo = tipoR[numero] if numero in tipoR else "Unknown error"
	body = bytes("<h1>"+str(numero)+" "+tipo+"</h1>"+debug.replace("\n","\n<br/>").replace(" ","&nbsp;"),encoding="UTF-8")
	richiesta.mandaHeaders(req,numero,[('Content-Length',str(len(body)))])
	rete.scrivi(req.connessione,body)

def serveStatic(req, path, root):
	if path =="":
		path = "./"
	if path[0] == "/":
		path = path[1:]
	#print(root)
	#print(path)
	root = os.path.realpath(root)
	path = os.path.join(root,path)
	serve = False
	#print(os.path.isfile(path))
	if os.path.isfile(path):
		try:
			real = os.path.realpath(path)
			if real.find(root) == 0:
				if real.find(".ini") == -1:
					serve = True
		except:
			raise e
	elif os.path.isdir(path):
		#print(req.headers.hostName)
		for name in config.host(req.headers.hostName)['Index'].split():
			tentativo = os.path.join(path,name)
			if os.path.isfile(tentativo):
				real = os.path.realpath(tentativo)
				serve = True
	if not serve:
		erroreHTTP(req,404,"File not found: "+req.headers.resource)
	else:
		stat = os.stat(real)
		lastm = time.gmtime(stat.st_mtime)
		ifModifiedSince = req.headers.get("if-modified-since")
		if ifModifiedSince != "":
			date = base.readRFC1123(ifModifiedSince)
			if date >= lastm:
				richiesta.mandaHeaders(req, 304, [])	#non cambiato, evviva la cache
				return
		mime, encoding = mimetypes.guess_type(real, strict=False)
		if mime == "text/html":
			mime += "; charset=UTF-8"
		headers = [	('Content-Type', mime or "text/html; charset=UTF-8"),
					('Content-Length', str(stat.st_size)),
					('Last-Modified', base.dateRFC1123(time.gmtime(stat.st_mtime)))
					]
		#print(headers)
		richiesta.mandaHeaders(req, 200, headers)
		if req.headers.method.lower() != "head":
			try:
				with open(real, "rb") as f:
					pack = f.read(rete.pacchetto)
					while pack:
						rete.scrivi(req.connessione, pack)
						pack = f.read(rete.pacchetto)
			except:
				raise
def serveWSGI(req,configKey,nomeGestore):
	pezzi = configKey['WebModule'].split(" ")
	if len(pezzi) == 2:
		mod = pezzi[1]
		path1 = os.path.realpath(pezzi[0])
		if path1 not in sys.path:
			sys.path.insert(0,path1)
	else:
		mod = pezzi[0]
	modulo = importlib.import_module(mod)
	environ = wsgi_compat.prepare_environ(req, richiesta.HttpUtils.myVersion,nomeGestore)
	start_response = wsgi_compat.RispostaWSGI(req)
	try:
		result = modulo.application(environ, start_response )
		try:
			for l in result:
				start_response.scrivi(l)
		except TypeError as e:
			try:
				start_response.scrivi(result)
			except:
				raise
		finally:
			start_response.manda()
	except NameError:
		erroreHTTP(req,500,"no \"application\" callable in "+mod)
		return
def gestisciHTTP(req):
	#print(hostName)
	
	configKey, risorsa, nomeGestore,baseDir = config.risolviPath(req.headers.resource, hostName = req.headers.hostName)
	if configKey is not None:
		oldDir = os.path.realpath("./")
		os.chdir(baseDir)
		try:
			if "Serve" in configKey:
				serveStatic(req, risorsa, os.path.realpath(configKey['Serve']))
				#setup environment dict
				#environ = wsgi_compat.prepare_environ(contenuto, headers, HttpUtils.myVersion)
			elif "WebModule" in configKey:
				serveWSGI(req,configKey,nomeGestore)
			else:
				erroreHTTP(req,417,"Non hai configurato alcun gestore nella sezione raggiunta da questo indirizzo")
		except:
			erroreHTTP(req,500,traceback.format_exc())
		finally:
			os.chdir(oldDir)
	else:
		erroreHTTP(req,0.07,"Probabilmente manca la sezione [/] nel file di configurazione relativo al gestore corrente")

